package com.qunchuang.netty;

import com.qunchuang.mapper.LiftAgvcTaskMapper;
import com.qunchuang.mapper.LiftMapper;
import com.qunchuang.pojo.entity.LiftEntity;
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.event.ApplicationStartedEvent;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.TimeUnit;



/**
 * 客户端
 */
@Component
@Slf4j
@RequiredArgsConstructor
    //public class Client implements InitializingBean {
public class Client {
    private final LiftAgvcTaskMapper liftAgvcTaskMapper;
    //    @Autowired
    private final LiftMapper liftMapper;

    private final  ServerHandlerInit inits;
    private final  ReconnectClient reconnectClient;

//    public static final HashMap<ChannelFuture, String> CHANNEL = new HashMap<>();
    public static final HashMap<String, ChannelFuture> CHANNEL = new HashMap<>();

//    public void connect(int port, String host,String liftId) throws Exception{
//
//        /**
//         * 客户端的NIO线程组
//         *
//         */
//        EventLoopGroup group = new NioEventLoopGroup();
//
//        try {
//            /**
//             * Bootstrap 是一个启动NIO服务的辅助启动类 客户端的
//             */
//            Bootstrap bootstrap = new Bootstrap();
//            /**
//             * 设置group
//             */
//            bootstrap = bootstrap.group(group);
//            /**
//             * 关联客户端通道
//             */
//            bootstrap = bootstrap.channel(NioSocketChannel.class).option(ChannelOption.TCP_NODELAY, true);
//            /**
//             * 设置 I/O处理类,主要用于网络I/O事件，记录日志，编码、解码消息
//             */
//            bootstrap = bootstrap.handler(inits);
//
//            System.out.println("netty client start success!");
//
//            /**
//             * 连接服务端
//             */
//            ChannelFuture f = bootstrap.connect(host, port).sync();
//            CHANNEL.put(liftId,f);
//            log.info("连接tcp添加数据{}",CHANNEL.get(liftId));
////            Map<ChannelId,String> I = new HashMap<>();
////            Map<String, ChannelFuture> O = new  HashMap<>();
////            f.channel().writeAndFlush()
//            Channel channel = f.channel();
////            ChannelId channelId = channel.id();
////            ByteBuf buffer = Unpooled.buffer(10);
////            buffer.writeByte(0xaa);
////            buffer.writeByte(0x09);
////            buffer.writeByte(0x00);
////            buffer.writeByte(0x00);
////            buffer.writeByte(0x40);
////            buffer.writeByte(0x00);
////            buffer.writeByte(0x00);
////            buffer.writeByte(0x00);
////            buffer.writeByte(0x49);
////            buffer.writeByte(0xbb);
////            log.info("发送命令：{}",buffer);
////            ChannelFuture channelFuture = channel.writeAndFlush(buffer);
//
////            System.out.println("发送命令：" + channelFuture);
////            System.out.println("ChannelId: " + channelId);
//            //通常需要写不断重连服务端
//            f.addListener((ChannelFutureListener) future -> {
//                if (!future.isSuccess()) {
//                    //重连交给后端线程执行
//                    future.channel().eventLoop().schedule(() -> {
//                        log.info("重连服务端...");
//                        try {
//                            log.info("再次执行连接");
//                            connect(port,host,liftId);
//                        } catch (Exception e) {
//                            //                        e.printStackTrace();
//                            log.error("连接失败。。。");
//                        }
//                    }, 3000, TimeUnit.MILLISECONDS);
//                } else {
//                    log.info("服务端连接成功...");
//                }
//            });
//            /**
//             * 等待连接端口关闭
//             */
////            f.channel().closeFuture().sync();
//
//        } finally {
//            /**
//             * 退出，释放资源
//             */
////            group.shutdownGracefully();
//        }
//    }



    /**
     * 通道初始化
     */
//    static class ServerHandlerInit extends ChannelInitializer<SocketChannel> {
//        @Override
//        protected void initChannel(SocketChannel ch) throws Exception {
//            ChannelPipeline pipeline = ch.pipeline();
//            // 解码出具体的数据类型
//            //该篇对解码器和编码器进行了详细说明，推荐阅读https://blog.csdn.net/tang_huan_11/article/details/133853786
////            pipeline.addLast("decoder", new StringDecoder());//解码和编码可以自己定义
////            pipeline.addLast(new Handler());//handler类是自己写的处理类
////            pipeline.addLast("encoder", new StringEncoder());
//            ByteBuf delimiter1 = Unpooled.copiedBuffer("aa".getBytes());
//            ByteBuf delimiter2 = Unpooled.copiedBuffer("bb".getBytes());
//            pipeline.addLast(new DelimiterBasedFrameDecoder(1024, delimiter1, delimiter2));
//            pipeline.addLast("decoder", new StringDecoder());//解码和编码可以自己定义
//            pipeline.addLast("encoder", new StringEncoder());
//            pipeline.addLast(new Handler(liftAgvcTaskMapper,liftMapper));
//        }
//    }

//    @Override
    @EventListener(classes = {ApplicationStartedEvent.class
    })
//    @Async //异步多线程注解
    //这个方法在服务启动时就会执行，即服务启动后则客户端就启动了 afterPropertiesSet
    public void start() throws Exception {
        List<LiftEntity> liftEntities = liftMapper.selectList(null);
        log.info("查询电梯表结果：{}",liftEntities);
        for (LiftEntity liftEntity : liftEntities) {
            String ip = liftEntity.getLiftIp();
            Integer port = liftEntity.getLiftPort();
            String liftId = liftEntity.getLiftId();
            log.info("电梯ip为：{},电梯端口号为：{},电梯id为：{}",ip,port,liftId);
            reconnectClient.connect(port,ip,liftId);
//            connect(port,ip,liftId);//TCP工具做服务端进行测试的时候的端口和ip
        }
    }
}
